package com.neuedu.bases;


import com.neuedu.configs.PathConfig;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;


/**
 * @author Wujg(helpbusiness @ 126.com)
 * @date 2023/8/20
 */




public class BasePage {
    private ChromeDriver driver;

    private static final Logger logger = new Logger(BasePage.class.getName());

    public BasePage(ChromeDriver driver) {
        this.driver = driver;
    }

    //退出浏览器
    public void quit() {
        driver.quit();
        logger.info("****** Quit browser ******.");
    }

    //关闭当前window
    public void close() {
        try {
            driver.close();
            logger.info("Close window or browser.");
        } catch (Exception e) {
            logger.error("Failed to close window or browser! " + e.getMessage());
        }
    }

    //清空cookies

    public void clearCookies() {
        driver.manage().deleteAllCookies();
        logger.info("Clear cookies.");
    }

    //刷新浏览器
    public void refresh() {
        driver.navigate().refresh();
        waitSleep(3);
        logger.info("Sleep for browser refresh.");
    }

    //浏览器前进操作
    public void forward() {
        driver.navigate().forward();
        logger.info("Browser forward.");
    }

    //浏览器后退操作
    public void back() {
        driver.navigate().back();
        logger.info("Browser back.");
    }


    //截图
    public void saveScreenshot(String path) {

        String screenshotName;

        if(path != null)
            screenshotName = path;
        else
            screenshotName = getScreenshotFileName();

        try {
            File screenshotFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
            Files.move(screenshotFile.toPath(), Paths.get(screenshotName));
            logger.info("Saved a screenshot: " + screenshotName);
        } catch (IOException e) {
            logger.error("Failed to save a screenshot!" + e.getMessage());
        }
    }

    private String getScreenshotFileName() {
        LocalDateTime currentTime = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd  HH-mm-ss");
        String formattedTime = currentTime.format(formatter);
        String screenshotPath = PathConfig.path_screenshots;
        return screenshotPath + File.separator + formattedTime + ".png";
    }

    //sleep强制等待
    public static void waitSleep(int seconds) {
        if (seconds >= 5) {
            logger.info("Sleep " + seconds + "s.");
        }
        try {
            Thread.sleep(seconds * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //隐式等待
    public void waitImplicitly(int seconds) {
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(seconds));
        logger.info("Set implicitly_wait for " + seconds + " seconds.");
    }

    //显示等待 元素可见
    public boolean waitForElementVisibility(By locator) {
        try {
            Duration timeout = Duration.ofSeconds(10);
            Duration pollFrequency = Duration.ofMillis(500);
            long start = System.currentTimeMillis();

            WebDriverWait wait = new WebDriverWait(driver, timeout, pollFrequency);
            WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(locator));

            long end = System.currentTimeMillis();
            long waitTime = (end - start) / 1000; // 转换为秒

            logger.info("Wait element visible: " + locator.toString() + ". " + waitTime + "s");
            return true;
        } catch (Exception e) {
            logger.error("Failed to wait element visible: " + locator.toString() + "! " + e.getMessage());
            // this.saveScreenshot();  // 调用保存截图方法
            // throw e;
            return false;
        }
    }

    // 元素定位
    public WebElement findElement(By locator) throws NoSuchElementException {
        try {
            waitForElementVisibility(locator);
            WebElement element = driver.findElement(locator);
            // logger.info("Find element: " + locator.toString() + ".");
            return element;
        } catch (NoSuchElementException e) {
            logger.error("Failed to find element: " + locator.toString() + "! " + e.getMessage());
            // this.saveScreenshot();  // 调用保存截图方法
            throw e;
        }
    }

    //多元素定位
    public List<WebElement> findElements(By locator) throws NoSuchElementException {
        try {
            waitForElementVisibility(locator);
            List<WebElement> elements = driver.findElements(locator);
            logger.info("Find elements: " + locator.toString() + ".");
            return elements;
        } catch (NoSuchElementException e) {
            logger.error("Failed to find elements: " + locator.toString() + "! " + e.getMessage());
            // this.saveScreenshot();  // 调用保存截图方法
            throw e;
        }
    }

    //清空内容并输入数据
    public void sendKeys(By locator, String text) throws NoSuchElementException {
        WebElement element = findElement(locator);
        element.clear();
        try {
            element.sendKeys(text);
            logger.info("Send_keys '" + text + "' to : " + locator.toString());
        } catch (Exception e) {
            logger.error("Failed to send_keys : " + locator.toString() + "! " + e.getMessage());
            // this.saveScreenshot();  // 调用保存截图方法
        }
    }

    //清空内容
    public void clearContent(By locator) throws NoSuchElementException {
        WebElement element = findElement(locator);
        try {
            element.clear();
            logger.info("Clear content : " + locator.toString());
        } catch (Exception e) {
            logger.error("Failed to clear content : " + locator.toString() + "! " + e.getMessage());
            // this.saveScreenshot();  // 调用保存截图方法
        }
    }

    //单击
    public void click(By locator) throws NoSuchElementException {
        WebElement element = findElement(locator);
        try {
            element.click();
            waitSleep(1); // 调用等待方法
            logger.info("Click : " + locator.toString());
        } catch (Exception e) {
            logger.error("Failed to click : " + locator.toString() + "! " + e.getMessage());
        }
    }

    //双击
    public void doubleClick(By locator) throws NoSuchElementException {
        Actions actionChains = new Actions(driver);
        WebElement element = findElement(locator);
        try {
            actionChains.doubleClick(element).perform();
            logger.info("Double click : " + locator.toString());
        } catch (Exception e) {
            logger.error("Failed to double click : " + locator.toString() + "! " + e.getMessage());
        }
    }

    //js点击
    public void clickJS(By locator) throws NoSuchElementException {
        WebElement element = findElement(locator);
        try {
            JavascriptExecutor jsExecutor = (JavascriptExecutor) driver;
            jsExecutor.executeScript("arguments[0].click();", element);
            logger.info("JS_Click : " + locator.toString());
        } catch (Exception e) {
            logger.error("Failed to js_click : " + locator.toString() + "! " + e.getMessage());
        }
    }

    //获取网页标题
    public String getPageTitle() throws NoSuchWindowException {
        try {
            String pageTitle = driver.getTitle();
            logger.info("Page title is : " + pageTitle);
            return pageTitle;
        } catch (Exception e) {
            logger.error("Failed to get page title! " + e.getMessage());
            throw new NoSuchWindowException(e.getMessage());
        }
    }

    //获取浏览器位置
    public String getWindowPosition() {
        try {
            JavascriptExecutor jsExecutor = (JavascriptExecutor) driver;
            long posX = (long) jsExecutor.executeScript("return window.screenX;");
            long posY = (long) jsExecutor.executeScript("return window.screenY;");
            logger.info("Window position is : " + posX + ", " + posY);
            return posX + ", " + posY;
        } catch (Exception e) {
            logger.error("Failed to get window position! " + e.getMessage());
            throw e;
        }
    }

    //设置浏览器位置
    public void setWindowPosition(int x, int y) {
        try {
            Point position = new Point(x, y);
            driver.manage().window().setPosition(position);
            logger.info("Set window position : " + x + ", " + y);
        } catch (Exception e) {
            logger.error("Failed to set window position! " + e.getMessage());
            throw e;
        }
    }

    // 高亮元素
    public void highlightElement(By locator) {
        try {
            WebElement element = driver.findElement(locator);
            JavascriptExecutor jsExecutor = (JavascriptExecutor) driver;
            jsExecutor.executeScript("arguments[0].setAttribute('style', 'border: 2px solid red;');", element);
            // jsExecutor.executeScript("arguments[0].setAttribute('style', 'background: green; border: 2px solid red;');", element);
        } catch (Exception e) {
            logger.error("Failed to highlight element! " + e.getMessage());
            throw e;
        }
    }

    //设置页面对象的属性值
    public void setAttribute(By locator, String attributeName, String value) {
        try {
            WebElement element = driver.findElement(locator);
            JavascriptExecutor jsExecutor = (JavascriptExecutor) driver;
            jsExecutor.executeScript("arguments[0].setAttribute(arguments[1], arguments[2]);",
                    element, attributeName, value);
        } catch (Exception e) {
            logger.error("Failed to set attribute value! " + e.getMessage());
            throw e;
        }
    }

    //滚动到顶部
    public void scrollTop() {
        try {
            JavascriptExecutor jsExecutor = (JavascriptExecutor) driver;
            jsExecutor.executeScript("window.scrollTo(0, 0);");
        } catch (Exception e) {
            logger.error("Failed to scroll to top! " + e.getMessage());
            throw e;
        }
    }

    //滚动到底部
    public void scrollBottom() {
        try {
            JavascriptExecutor jsExecutor = (JavascriptExecutor) driver;
            jsExecutor.executeScript("window.scrollTo(0, document.body.scrollHeight);");
        } catch (Exception e) {
            logger.error("Failed to scroll to bottom! " + e.getMessage());
            throw e;
        }
    }

    //移动到元素element对象的“顶端”与当前窗口的“顶部”对齐
    public void scrollElement(By locator) {
        try {
            WebElement element = driver.findElement(locator);
            JavascriptExecutor jsExecutor = (JavascriptExecutor) driver;
            jsExecutor.executeScript("arguments[0].scrollIntoView();", element);
        } catch (Exception e) {
            logger.error("Failed to scroll to element! " + e.getMessage());
            throw e;
        }
    }

    // 显示等待 元素从dom中消失
    public boolean waitElementStaleness(By locator) {
        try {


            WebDriverWait wait = new WebDriverWait(driver,  Duration.ofSeconds(20));
            wait.until(ExpectedConditions.stalenessOf(driver.findElement(locator)));
            return true;
        } catch (Exception e) {
            logger.error("Failed to wait for element staleness! " + e.getMessage());
            throw e;
        }
    }

    //显示等待 元素可见
    public boolean waitElementNotClickable(By locator) {
        try {
            long startTime = System.currentTimeMillis();
            WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
            wait.until(ExpectedConditions.not(ExpectedConditions.elementToBeClickable(locator)));
            long endTime = System.currentTimeMillis();
            long waitTime = (endTime - startTime) / 1000; // 转换为秒
            logger.info("Wait element not clickable: " + locator + " | Time: " + waitTime + "s");
            return true;
        } catch (Exception e) {
            logger.error("Failed to wait for element not clickable: " + locator + " | " + e.getMessage());
            throw e;
        }
    }

    //获取文本内容
    public String getTextF(By locator) {
        WebElement element = findElement(locator);
        try {
            String text = element.getText();

            logger.info("get_text "+ text+" to " + locator);
            return text;
        } catch (Exception e) {
            logger.error("Failed to get_text " + locator + " to " + e.getMessage());
            // save_screenshot_f();
            return null;
        }
    }

    // 获取用户名密码:
    //public static Map<String, String> getUserLoginDatas(String userType) {
    //    Map<String, Map<String, String>> roleData = new HashMap<>();
    //
    //    // 添加不同用户类型的用户名和密码数据
    //    Map<String, String> managerData = new HashMap<>();
    //    managerData.put("username", "manager_username");
    //    managerData.put("password", "manager_password");
    //    roleData.put("manager", managerData);
    //
    //    // HandleYaml userHandle = new HandleYaml("roles_login.yaml");
    //    // Map<String, Map<String, String>> roleDic = userHandle.getData();
    //    Map<String, Map<String, String>> roleDic = null; // 从yaml文件中读取角色登录数据
    //
    //    if (roleDic != null) {
    //        try {
    //            Map<String, String> userDic = roleDic.get(userType);
    //            return userDic;
    //        } catch (Exception e) {
    //            Map<String, String> userData = roleData.get(userType);
    //            // userHandle.writeData(userType, userData.get("username"), userData.get("password"));
    //            return userData;
    //        }
    //    } else {
    //        Map<String, String> userData = roleData.get(userType);
    //        // userHandle.writeData(userType, userData.get("username"), userData.get("password"));
    //        return userData;
    //    }
    //}

    // 查找元素是否存在，若消失，返回null
    public WebElement checkEleF(By locator) {
        try {
            WebElement ele = new WebDriverWait(driver, Duration.ofSeconds(2)).until(ExpectedConditions.visibilityOfElementLocated(locator));
            logger.info("Wait element visible : " + locator);
            return ele;
        } catch (Exception e) {
            return null;
        }
    }

}